/**
  ******************************************************************************
  * File Name          : xc.c
  * Description        : 
  ******************************************************************************
  * @attention
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "bsp.h"
#include "xc.h"

#define XCCNT_TSK_PRIORITY                        (tskIDLE_PRIORITY + 3)
#define XCCNT_STACK_SIZE                          512u
TaskHandle_t xXcCnt_Thd = NULL;
StaticTask_t xXcCnt_Tcb;
StackType_t  xXcCnt_Stk[ XCCNT_STACK_SIZE ];

#define XCKEY_TSK_PRIORITY                        (tskIDLE_PRIORITY + 4)
#define XCKEY_STACK_SIZE                          512u
TaskHandle_t xXcKey_Thd = NULL;
StaticTask_t xXcKey_Tcb;
StackType_t  xXcKey_Stk[ XCKEY_STACK_SIZE ];

/* 除粪控制任务 */
#define XCACT_TSK_PRIORITY                        (tskIDLE_PRIORITY + 5)
#define XCACT_STACK_SIZE                          512u
TaskHandle_t xXcAct_Thd = NULL;
StaticTask_t xXcAct_Tcb;
StackType_t  xXcAct_Stk[ XCACT_STACK_SIZE ];

/* 485 接收消息队列 */
QueueHandle_t Xc_RxCmd_Qhd = NULL;
static StaticQueue_t xc_rxcmd_stru;
static uint8_t       xc_rxcmd_area[XC_RXCMDQUE_LENGTH * XC_RXCMDQUE_ITEMSIZE];

/* 输入检测信号量 */
SemaphoreHandle_t Xc_KeyDetect_Shd = NULL;
static StaticSemaphore_t xc_key_detect_area;

const Xc_ActionCmdType Xc_CmdReset = 
{
  .cmd = XC_ACTCMD_RESET,
  .dat = 0,
};

const Xc_ActionCmdType Xc_CmdMarkUpLimit = 
{
  .cmd = XC_ACTCMD_MARKUPLIMIT,
  .dat = 0,
};

const Xc_ActionCmdType Xc_CmdUp = 
{
  .cmd = XC_ACTCMD_UP,
  .dat = 0,
};

const Xc_ActionCmdType Xc_CmdDown = 
{
  .cmd = XC_ACTCMD_DOWN,
  .dat = 0,
};

static uint8_t xc_code_run_flag = 0;

static uint8_t xc_reset(void)
{
  uint8_t stable;
  int16_t timeout;
  uint32_t pos;
  
  XC_TIEROD_DOWN();
  
  pos = 0;
  timeout = (Xc_OutTime * 1000)/50;
  stable = 0;
  
  do
  {
    if(pos == Xc_GetPosition())
    {
      stable++;
    }
    else
    {
      stable = 0;
    }
    
    pos = Xc_GetPosition();
    
    vTaskDelay(50);
    
    if(timeout-- <= 0)
    {
      break;
    }
  }
  while(stable < 3);
  
  XC_TIEROD_STOP();
  
  Xc_ResetPosition();
  
  return 0;
}

static uint8_t xc_mark_uplimit(void)
{
  uint8_t stable;
  int16_t timeout;
  uint32_t pos;
  Xc_ActionCmdType rcmd;
  
  xc_reset();
  
  XC_TIEROD_PU();
  
  xQueueReset(Xc_RxCmd_Qhd);
  
  pos = 0;
  timeout = (Xc_OutTime * 1000)/50;
  stable = 0;
  
  do
  {
    if(xQueueReceive(Xc_RxCmd_Qhd, &rcmd, 50) == pdTRUE)
    {
      if(rcmd.cmd == XC_ACTCMD_MARKUPLIMIT)
      {
        XC_TIEROD_STOP();
        
        Xc_UpLimit = Xc_GetPosition();
        
        if(Storage_qhd != 0)
        {
          xQueueSend(Storage_qhd, &Xc_SaveUpLimit, 0);
        }
        
        printf("up limit:%d\r\n", Xc_UpLimit);
        
        return 0;
      }
    }
    
    if(pos == Xc_GetPosition())
    {
      stable++;
    }
    else
    {
      stable = 0;
    }
    
    if(timeout-- <= 0)
    {
      break;
    }
  }
  while(stable < 3);
  
  XC_TIEROD_STOP();
  
  return 1;
}

static uint8_t xc_action(uint8_t per)
{
  uint8_t stable, dir;
  int16_t timeout;
  uint16_t code;
  uint32_t pos;
  
  if(per == 0)
  {
    xc_reset();
    
    return 0;
  }
  
  code = Xc_PercentToCode(per);
  
  pos = Xc_GetPosition();
  if(code > pos)
  {
    Xc_SetPosition(code);
    XC_TIEROD_PU();
    dir = 0;
  }
  else if(code < pos)
  {
    Xc_SetPosition(code);
    XC_TIEROD_DOWN();
    dir = 1;
  }
  else
  {
    return 1;
  }
  
  pos = 0;
  timeout = (Xc_OutTime * 1000)/50;
  stable = 0;
  
  do
  {
    if(dir == 0)  /* 向上走 */
    {
      if((pos >= Xc_GetPosition()) || (Xc_GetPosition() >= code))
      {
        stable++;
      }
      else
      {
        stable = 0;
      }
    }
    else if(dir == 1)
    {
      if((pos <= Xc_GetPosition()) || (Xc_GetPosition() <= code))
      {
        stable++;
      }
      else
      {
        stable = 0;
      }
    }
    else
    {
    }
    
    pos = Xc_GetPosition();
    
    vTaskDelay(50);
    
    if(timeout-- <= 0)
    {
      break;
    }
  }
  while(stable < 3);
  
  XC_TIEROD_STOP();
  
  return 0;
}

uint8_t Xc_CodeToPercent(uint16_t code)
{
  uint32_t temp;
  
  if(code <= Xc_UpLimit)
  {
    temp = (uint32_t)code * 100;
    return(temp / Xc_UpLimit);
  }
  
  return 101;
}

uint16_t Xc_PercentToCode(uint8_t per)
{
  uint32_t temp;
  
  if(per < 100)
  {
    temp = (uint32_t)Xc_UpLimit * per;
    
    return (temp/100);
  }
  
  return Xc_UpLimit;
}

void Xc_UpdataCurrentPosition(void)
{
  uint32_t pos;
  uint8_t cpos;
  
  pos = Xc_GetPosition();
  printf("cops code:%u\r\n", pos);
  
  cpos = Xc_CodeToPercent(pos);
  printf("cops pcnt:%u\r\n", cpos);
  
  if(cpos != Xc_CurrentPosition)
  {
    Xc_CurrentPosition = cpos;
    
    if(Storage_qhd != 0)
    {
      xQueueSend(Storage_qhd, &Xc_SaveCurrentPosition, 0);
    }
  }
}

void vXcAct_Task( void * pvParameters )
{
	Xc_ActionCmdType rcmd;
	
	Xc_BspInit();
	
  Xc_RxCmd_Qhd = xQueueCreateStatic(XC_RXCMDQUE_LENGTH, \
                                    XC_RXCMDQUE_ITEMSIZE, \
                                    xc_rxcmd_area, \
                                    &xc_rxcmd_stru);
  /* 上电后复位 且回归保存位置 */
  xc_reset();
  xc_action(Xc_CurrentPosition);
  Xc_UpdataCurrentPosition();
  
	while(1)
	{
    if(xQueueReceive(Xc_RxCmd_Qhd, &rcmd, portMAX_DELAY) == pdTRUE)
    {
      switch(rcmd.cmd)
      {
        case XC_ACTCMD_RESET:
          xc_reset();
          break;
        
        case XC_ACTCMD_ACTION:
          xc_action(rcmd.dat);
          break;
        
        case XC_ACTCMD_MARKUPLIMIT:
          xc_mark_uplimit();
          break;
        
        case XC_ACTCMD_UP:
          break;
        
        case XC_ACTCMD_DOWN:
          break;

        default:
          break;
      }
      
      Xc_UpdataCurrentPosition();
    }
	}
}

void vXcKey_Task( void * pvParameters )
{
	Xc_KeyDetect_Shd = xSemaphoreCreateBinaryStatic(&xc_key_detect_area);
  
	while(1)
	{
		xSemaphoreTake(Xc_KeyDetect_Shd, 1000);
		
		if(Xc_KeyReset() == 0)
		{
			vTaskDelay(100);
			if(Xc_KeyReset() == 0)
			{
				vTaskDelay(100);
				if(Xc_KeyReset() == 0)
				{
					if(Xc_RxCmd_Qhd != NULL)
          {
            xQueueSend(Xc_RxCmd_Qhd, &Xc_CmdReset, 0);
          }
				}
			}
		}
		
		if(Xc_KeyMarkUpLimit() == 0)
		{
			vTaskDelay(100);
			if(Xc_KeyMarkUpLimit() == 0)
			{
				vTaskDelay(100);
				if(Xc_KeyMarkUpLimit() == 0)
				{
					if(Xc_RxCmd_Qhd != NULL)
          {
            xQueueSend(Xc_RxCmd_Qhd, &Xc_CmdMarkUpLimit, 0);
          }
				}
			}
		}
	}
}

void vXcCnt_Task( void * pvParameters )
{
  static uint32_t poslast;
  
  poslast = Xc_GetPosition();
  
	while(1)
	{
		if(poslast != Xc_GetPosition())
    {
      xc_code_run_flag = 1;
      XC_HARDLIGHT(1);
      
      poslast = Xc_GetPosition();
    }
    else
    {
      xc_code_run_flag = 0;
      XC_HARDLIGHT(0);
    }
    
    vTaskDelay(200);
	}
}

void Sys_RunLed(void)
{
  if(xc_code_run_flag != 0)
  {
    LED1(LED_On);
    vTaskDelay(700);
    LED1(LED_Off);
    vTaskDelay(300);
  }
  else
  {
    LED1(LED_On);
    vTaskDelay(300);
    LED1(LED_Off);
    vTaskDelay(700);
  }
}

void Expio_DevTaskCreat(void)
{
	xXcAct_Thd = xTaskCreateStatic(vXcAct_Task,
																 "XcxAc",
																 XCACT_STACK_SIZE,
																 (void *)1,
																 XCACT_TSK_PRIORITY,
																 xXcAct_Stk,
																 &xXcAct_Tcb);
                                 
  xXcKey_Thd = xTaskCreateStatic(vXcKey_Task,
																 "XcKey",
																 XCKEY_STACK_SIZE,
																 (void *)1,
																 XCKEY_TSK_PRIORITY,
																 xXcKey_Stk,
																 &xXcKey_Tcb);
                                 
  xXcCnt_Thd = xTaskCreateStatic(vXcCnt_Task,
																 "Cnt",
																 XCCNT_STACK_SIZE,
																 (void *)1,
																 XCCNT_TSK_PRIORITY,
																 xXcCnt_Stk,
																 &xXcCnt_Tcb);
}
